package com.yfp.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.hy.corecode.idgen.WFGIdGenerator;
import com.yfp.common.core.exception.ServiceException;
import com.yfp.common.core.utils.PageUtils;
import com.yfp.common.core.web.page.TableDataInfo;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.enums.ActivitySignInsRewardTypeEnums;
import com.yfp.operation.enums.ActivitySignInsStatusEnums;
import com.yfp.operation.mapper.ActivitySignInsMapper;
import com.yfp.operation.mapper.MarketingMapper;
import com.yfp.operation.service.*;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 * @description 针对表【activity_sign_ins(打卡管理主表)】的数据库操作Service实现
 * @createDate 2025-01-02 10:22:14
 */
@Slf4j
@Service
public class ActivitySignInsServiceImpl extends ServiceImpl<ActivitySignInsMapper, ActivitySignIns> implements ActivitySignInsService {

    @Resource
    private ActivitySignInsMapper activitySignInsMapper;
    @Resource
    private ActivitySignInsRulesService activitySignInsRulesService;
    @Resource
    private ActivitySignInsClientsService activitySignInsClientsService;
    @Resource
    private ActivitySignInsClientRecordsService activitySignInsClientRecordsService;
    @Resource
    private MarCouponService marCouponService;
    @Resource
    private MarCouponPackService marCouponPackService;
    @Resource
    private MarketingMapper marketingMapper;
    @Resource
    private WFGIdGenerator wfgIdGenerator;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(ActivitySignInsCreateReqDTO activitySignInsCreateReqDTO) {
        Boolean check = this.createCheck(activitySignInsCreateReqDTO);
        Assert.isTrue(check, "当前已有进行中的活动，无法新建，请结束后再创建");
        this.createCheck2(activitySignInsCreateReqDTO);

        // 锁扣减库存
        activitySignInsRulesService.lockInventory(activitySignInsCreateReqDTO.getActivitySignInsRulesList());

        ActivitySignIns activitySignIns = BeanUtil.toBean(activitySignInsCreateReqDTO, ActivitySignIns.class);
        activitySignIns.setStatus(this.calculateStatus(activitySignIns.getStartTime(), activitySignIns.getEndTime()));
        activitySignIns.setDeptId(SecurityUtils.getLoginUser().getSysUser().getDeptId());
        activitySignIns.setCreateUserId(SecurityUtils.getLoginUser().getSysUser().getUserId());
        activitySignIns.setCreateTime(DateUtil.date());
        activitySignInsMapper.add(activitySignIns);

        Marketing marketing = new Marketing();
        marketing.setType(5);
        marketing.setId(wfgIdGenerator.next());
        marketing.setActivitySignInsId(activitySignIns.getId());
        marketingMapper.add(marketing);

        List<ActivitySignInsRules> activitySignInsRules = BeanUtil.copyToList(activitySignInsCreateReqDTO.getActivitySignInsRulesList(), ActivitySignInsRules.class);
        activitySignInsRules.forEach(item -> {
            item.setActivitySignInsId(activitySignIns.getId());
            item.setResidualInventory(item.getTotalInventory());
        });
        activitySignInsRulesService.saveBatch(activitySignInsRules);
    }

    @Override
    public TableDataInfo<ActivitySignInsSearchReqVO> searchList(ActivitySignInsSearchReqDTO searchReqDTO) {

        PageUtils.startPage();
        List<ActivitySignIns> activitySignIns = activitySignInsMapper.searchList(searchReqDTO);
        long total = new PageInfo(activitySignIns).getTotal();

        List<Long> activitySignInsIds = activitySignIns.stream().map(ActivitySignIns::getId).toList();
        HashMap<Long, Long> countByActivitySignInsIds = activitySignInsClientsService.countByActivitySignInsIds(activitySignInsIds);

        List<ActivitySignInsSearchReqVO> signInsSearchReqVOList = BeanUtil.copyToList(activitySignIns, ActivitySignInsSearchReqVO.class);
        signInsSearchReqVOList.stream().forEach(item -> {
            item.setUserCount(countByActivitySignInsIds.getOrDefault(item.getId(), 0L));
        });

        TableDataInfo<ActivitySignInsSearchReqVO> dataTable = PageUtils.getDataTable(signInsSearchReqVOList);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public TableDataInfo<ActivitySignInsSearchRewardReqVO> searchRewardList(ActivitySignInsSearchRewardReqDTO searchReqDTO) {

        List<ActivitySignInsRules> activitySignInsRules = activitySignInsRulesService.searchList(searchReqDTO);

        List<ActivitySignInsSearchRewardReqVO> signInsSearchReqVOList = activitySignInsRules.stream().map(item -> {
            ActivitySignInsSearchRewardReqVO bean = BeanUtil.toBean(item, ActivitySignInsSearchRewardReqVO.class);
            // 奖品Name
            bean.setRewardName(this.getRewardName(item.getRewardId(), item.getRewardType()));
            // 奖品Name
            bean.setCityName(this.getCityName(item.getRewardId(), item.getRewardType()));
            // 发放数量
            bean.setGrantQuantity(item.getTotalInventory() - item.getResidualInventory());
            return bean;
        }).filter(item -> {
            if (StrUtil.isNotBlank(searchReqDTO.getRewardName())) {
                return StrUtil.contains(item.getRewardName(), searchReqDTO.getRewardName());
            }
            return true;
        }).toList();

        return PageUtils.getDatableByStream(signInsSearchReqVOList);
    }

    @Override
    public TableDataInfo<ActivitySignInsSearchParticipationReqVO> searchParticipationList(ActivitySignInsSearchParticipationReqDTO searchReqDTO) {
        ActivitySignIns activitySignIns = activitySignInsMapper.selectById(searchReqDTO.getActivitySignInsId());
        Assert.notNull(activitySignIns, "不存在该活动");
        ActivitySignInsSearchParticipationReq2DTO searchReq2DTO = BeanUtil.toBean(searchReqDTO, ActivitySignInsSearchParticipationReq2DTO.class);
        searchReq2DTO.setStartTime(activitySignIns.getStartTime());
        searchReq2DTO.setEndTime(activitySignIns.getEndTime());

        PageUtils.startPage();
        List<ActivitySignInsSearchParticipationReqVO> activitySignInsSearchParticipationReqVOS = activitySignInsClientsService.searchParticipationList(searchReq2DTO);
        long total = new PageInfo(activitySignInsSearchParticipationReqVOS).getTotal();

        TableDataInfo<ActivitySignInsSearchParticipationReqVO> dataTable = PageUtils.getDataTable(activitySignInsSearchParticipationReqVOS);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public TableDataInfo<ActivitySignInsSearchParticipationAwardReqVO> searchParticipationAwardList(ActivitySignInsSearchParticipationAwardReqDTO searchReqDTO) {
        List<ActivitySignInsRules> activitySignInsRulesList = activitySignInsRulesService.listByActivitySignInsId(searchReqDTO.getActivitySignInsId());
        Map<Long, ActivitySignInsRules> activitySignInsRulesMap = activitySignInsRulesList.stream().collect(Collectors.toMap(ActivitySignInsRules::getId, item -> item));
        List<ActivitySignInsClientRecords> activitySignInsClientRecords = activitySignInsClientRecordsService.searchParticipationAwardList(searchReqDTO);

        List<ActivitySignInsSearchParticipationAwardReqVO> list = activitySignInsClientRecords.stream().map(item -> {
            ActivitySignInsSearchParticipationAwardReqVO awardReqVO = new ActivitySignInsSearchParticipationAwardReqVO();
            ActivitySignInsRules activitySignInsRules = activitySignInsRulesMap.get(item.getActivitySignInsRuleId());
            awardReqVO.setRules(activitySignInsRules.getRules());
            awardReqVO.setRewardId(activitySignInsRules.getRewardId());
            // 奖品Name
            awardReqVO.setRewardName(this.getRewardName(item.getRewardId(), item.getRewardType()));
            awardReqVO.setCityName(this.getCityName(item.getRewardId(), item.getRewardType()));
            awardReqVO.setRewardType(activitySignInsRules.getRewardType());
            awardReqVO.setTime(item.getReceiveTime());
            return awardReqVO;
        }).toList();

        return PageUtils.getDatableByStream(list);
    }

    @Override
    public ActivitySignInsVO getInfo(Long id) {
        ActivitySignIns activitySignIns = activitySignInsMapper.selectById(id);
        List<ActivitySignInsRules> activitySignInsRules = activitySignInsRulesService.listByActivitySignInsId(id);

        ActivitySignInsVO activitySignInsVO = BeanUtil.toBean(activitySignIns, ActivitySignInsVO.class);
        List<ActivitySignInsRulesVO> activitySignInsRulesVOS = activitySignInsRules.stream().map(item -> {
            ActivitySignInsRulesVO activitySignInsRulesVO = BeanUtil.toBean(item, ActivitySignInsRulesVO.class);
            // 奖品Name
            activitySignInsRulesVO.setRewardName(this.getRewardName(item.getRewardId(), item.getRewardType()));
            return activitySignInsRulesVO;
        }).toList();

        activitySignInsVO.setActivitySignInsRulesVOList(activitySignInsRulesVOS);
        return activitySignInsVO;
    }

    @Override
    public void failure(Long id) {
        activitySignInsMapper.updateStatusById(id, ActivitySignInsStatusEnums.INVALIDATED.getCode());
    }

    @Override
    public void delete(Long id) {
        activitySignInsMapper.updateStatusById(id, ActivitySignInsStatusEnums.DELETED.getCode());
    }

    @Override
    public Boolean createCheck(ActivitySignInsCreateReqDTO activitySignInsCreateReqDTO) {
        List<Integer> statusList = Arrays.asList(ActivitySignInsStatusEnums.ONGOING.getCode(), ActivitySignInsStatusEnums.AWAIT_START.getCode());
        List<ActivitySignIns> activitySignInsList = activitySignInsMapper.selectByCityNameAndStatus(activitySignInsCreateReqDTO.getCityName(), statusList);

        return CollUtil.isEmpty(activitySignInsList);
    }

    @Override
    public void createCheck2(ActivitySignInsCreateReqDTO activitySignInsCreateReqDTO) {

        // 优惠券状态校验
        List<ActivitySignInsRulesCreateReqDTO> marCouponList = activitySignInsCreateReqDTO.getActivitySignInsRulesList().stream()
                .filter(item -> CollUtil.contains(ActivitySignInsRewardTypeEnums.getMarCouponList(), item.getRewardType())).toList();
        if (CollUtil.isNotEmpty(marCouponList)) {
            // 校验 礼包内容是否有 1进行中，4待开始之外的券状态。状态[0删除、1进行中、2已失效、3已过期、4待开始]
            List<MarCoupon> marCoupons = marCouponService.listByIds(marCouponList.stream().map(ActivitySignInsRulesCreateReqDTO::getRewardId).collect(Collectors.toList()));
            Map<Long, MarCoupon> marCouponMapById = marCoupons.stream().collect(Collectors.toMap(MarCoupon::getId, Function.identity()));
            marCouponList.forEach(item -> {
                MarCoupon marCoupon = marCouponMapById.getOrDefault(item.getRewardId(), null);
                if (Objects.isNull(marCoupon)) {
                    throw new ServiceException(String.format("无此[%s]优惠券", item.getRewardId()));
                }
                if (CollUtil.safeContains(Arrays.asList(0, 2, 3), marCoupon.getStatus())) {
                    throw new ServiceException(String.format("[%s]状态异常", marCoupon.getCouponName()));
                }
                if (!NumberUtil.isIn(NumberUtil.toBigDecimal(item.getDistributionQuantity()), BigDecimal.ONE, NumberUtil.toBigDecimal(marCoupon.getReceiveCount()))) {
                    throw new ServiceException(String.format("[%s]赠券数需要小于等于每人限领次数", marCoupon.getCouponName()));
                }
            });
        }

        // =============================

        // 礼包校验
        List<ActivitySignInsRulesCreateReqDTO> marCouponPackList = activitySignInsCreateReqDTO.getActivitySignInsRulesList().stream()
                .filter(item -> CollUtil.contains(ActivitySignInsRewardTypeEnums.getMarCouponPackList(), item.getRewardType())).toList();
        if (CollUtil.isNotEmpty(marCouponPackList)) {
            List<MarCouponPack> couponPackList = marCouponPackService.findByIds(marCouponPackList.stream().map(ActivitySignInsRulesCreateReqDTO::getRewardId).collect(Collectors.toList()));
            Map<Long, MarCouponPack> marCouponPackMapById = couponPackList.stream().collect(Collectors.toMap(MarCouponPack::getId, Function.identity()));
            marCouponPackList.forEach(item -> {
                MarCouponPack marCouponPack = marCouponPackMapById.getOrDefault(item.getRewardId(), null);
                if (Objects.isNull(marCouponPack)) {
                    throw new ServiceException(String.format("无此[%s]礼包", item.getRewardId()));
                }
                if (CollUtil.safeContains(Arrays.asList(0, 2), marCouponPack.getStatus())) {
                    throw new ServiceException(String.format("[%s]状态异常", marCouponPack.getPackName()));
                }
            });
        }

    }

    @Override
    public String getRewardName(Long rewardId, Integer rewardType) {

        List<Integer> marCouponList = Arrays.asList(ActivitySignInsRewardTypeEnums.COUPON.getCode(), ActivitySignInsRewardTypeEnums.ENTITY_GOODS.getCode());
        List<Integer> marCouponPackList = Arrays.asList(ActivitySignInsRewardTypeEnums.GIFT_PACKAGE.getCode());

        if (CollUtil.contains(marCouponList, rewardType)) {
            MarCoupon marCoupon = marCouponService.getById(rewardId);
            return marCoupon.getCouponName();
        } else if (CollUtil.contains(marCouponPackList, rewardType)) {
            MarCouponPack couponPack = marCouponPackService.getById(rewardId);
            return couponPack.getPackName();
        }

        return "";
    }

    @Override
    public String getCityName(Long rewardId, Integer rewardType) {
        List<Integer> marCouponList = Arrays.asList(ActivitySignInsRewardTypeEnums.COUPON.getCode(), ActivitySignInsRewardTypeEnums.ENTITY_GOODS.getCode());
        List<Integer> marCouponPackList = Arrays.asList(ActivitySignInsRewardTypeEnums.GIFT_PACKAGE.getCode());

        if (CollUtil.contains(marCouponList, rewardType)) {
            MarCoupon marCoupon = marCouponService.getById(rewardId);
            return marCoupon.getCityName();
        } else if (CollUtil.contains(marCouponPackList, rewardType)) {
            MarCouponPack couponPack = marCouponPackService.getById(rewardId);
            return couponPack.getCityName();
        }

        return "";
    }

    @Override
    public Integer calculateStatus(Date startTime, Date endTime) {
        // 状态:[1:进行中,3:已过期,4:待开始]
        DateTime date = DateUtil.date();
        if (date.isBefore(startTime)) {
            // 待开始
            return ActivitySignInsStatusEnums.AWAIT_START.getCode();
        } else if (date.isIn(startTime, endTime)) {
            // 进行中
            return ActivitySignInsStatusEnums.ONGOING.getCode();
        } else {
            // 已过期
            return ActivitySignInsStatusEnums.EXPIRED.getCode();
        }
    }

    @Override
    public void incrementCount(String clientId, String cityName) {
        log.info("incrementCount:clientId:{},cityName:{}", clientId, cityName);
        ActivitySignIns activitySignIns = activitySignInsMapper.getByStatus(ActivitySignInsStatusEnums.ONGOING.getCode(), cityName);
        if (Objects.isNull(activitySignIns)) {
            return;
        }

        if (!ActivitySignInsStatusEnums.ONGOING.getCode().equals(activitySignIns.getStatus())) {
            return;
        }

        if (!activitySignInsClientsService.joined(clientId, activitySignIns.getId())) {
            return;
        }

        List<ActivitySignInsRules> activitySignInsRules = activitySignInsRulesService.listByActivitySignInsId(activitySignIns.getId());
        // 获取最大规则
        ActivitySignInsRules maxSignInsRules = activitySignInsRules.stream().max(Comparator.comparing(ActivitySignInsRules::getRules)).orElse(null);
        if (Objects.isNull(maxSignInsRules)){
            return;
        }

        Long currentCount = activitySignInsClientsService.currentCount(clientId, activitySignIns.getId());
        if (NumberUtil.isLess(NumberUtil.toBigDecimal(currentCount), NumberUtil.toBigDecimal(maxSignInsRules.getRules()))) {
            activitySignInsClientsService.incrementCount(clientId, activitySignIns.getId());
        }

    }

    @Override
    public void checkAndUpdateAllStatus() {
        // 获取进行中的活动
        List<ActivitySignIns> activitySignIns = activitySignInsMapper.selectByStatus(ActivitySignInsStatusEnums.ONGOING.getCode());
        activitySignIns.stream().forEach(item -> {
            Integer status = this.calculateStatus(item.getStartTime(), item.getEndTime());
            if (!item.getStatus().equals(status)) {
                activitySignInsMapper.updateStatusById(item.getId(), status);
            }
        });

        // 获取待开始的活动
        List<ActivitySignIns> activitySignIns1 = activitySignInsMapper.selectByStatus(ActivitySignInsStatusEnums.AWAIT_START.getCode());
        activitySignIns1.stream().forEach(item -> {
            Integer status = this.calculateStatus(item.getStartTime(), item.getEndTime());
            if (!item.getStatus().equals(status)) {
                activitySignInsMapper.updateStatusById(item.getId(), status);
            }
        });

    }
}




